home *** CD-ROM | disk | FTP | other *** search
/ Aminet 21 / Aminet 21 (1997)(GTI - Schatztruhe)[!][Oct 1997].iso / Aminet / dev / misc / ahidev.lha / AHI / Developer / drivers / filesave / filesave.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-04-29  |  22.5 KB  |  862 lines

  1.  
  2. #define NO_PROTOS
  3. #define NO_SAS_PRAGMAS
  4. #include <iffp/8svx.h>
  5. #undef NO_PROTOS
  6. #undef NO_SAS_PRAGMAS
  7.  
  8. #include <exec/exec.h>
  9. #include <devices/ahi.h>
  10. #include <dos/dos.h>
  11. #include <dos/dostags.h>
  12. #include <graphics/gfxbase.h>
  13. #include <libraries/ahi_sub.h>
  14. #include <libraries/asl.h>
  15. #include <datatypes/datatypes.h>
  16. #include <datatypes/soundclass.h>
  17. #include <proto/asl.h>
  18. #include <proto/exec.h>
  19. #include <proto/dos.h>
  20. #include <proto/intuition.h>
  21. #include <proto/utility.h>
  22. #include <proto/datatypes.h>
  23. #include <proto/ahi_sub.h>
  24. #include <stdlib.h>
  25. #include "filesave.h"
  26.  
  27. #define EQ ==
  28. #define dd ((struct filesave *) AudioCtrl->ahiac_DriverData)
  29.  
  30. #define SAVEBUFFERSIZE 100000   // in samples (min)
  31. #define RECBUFFERSIZE  10000    // in samples
  32.  
  33. extern char __far _LibID[];
  34. extern char __far _LibName[];
  35.  
  36. extern void KPrintF(char *fmt,...);
  37.  
  38. #define FREQUENCIES 19
  39. const ULONG  frequency[FREQUENCIES] =
  40. {
  41.   8000,     // ยต- and A-Law
  42.   9600,     // DAT/5
  43.   11025,    // CD/4
  44.   12000,    // DAT/4
  45.   14700,    // CD/3
  46.   16000,    // DAT/3
  47.   17640,    // CD/2.5
  48.   18900,
  49.   19200,    // DAT/2.5
  50.   22050,    // CD/2
  51.   24000,    // DAT/2
  52.   29400,    // CD/1.5
  53.   32000,    // DAT/1.5
  54.   37800,
  55.   44056,    // Some kind of video rate
  56.   44100,    // CD
  57.   48000,    // DAT
  58.   88200,    // CD*2
  59.   96000     // DAT*2
  60. };
  61.  
  62. extern void SlaveEntry(void);
  63. extern void RecSlaveEntry(void);
  64. void ulong2extended (ULONG in, extended *ex);
  65.  
  66. struct DosLibrary     *DOSBase=NULL;
  67. struct Library        *UtilityBase=NULL;
  68. struct Library        *AslBase=NULL;
  69. struct IntuitionBase  *IntuitionBase=NULL;
  70. struct Library        *AHIsubBase=NULL;
  71. struct Library        *DataTypesBase=NULL;
  72. struct GfxBase        *GfxBase=NULL;
  73.  
  74. int  __saveds __asm __UserLibInit (register __a6 struct Library *libbase)
  75. {
  76.   AHIsubBase=libbase;
  77.  
  78.   if(!(DOSBase=(struct DosLibrary *)OpenLibrary("dos.library",37)))
  79.   {
  80.     Alert(AN_Unknown|AG_OpenLib|AO_DOSLib);
  81.     return 1;
  82.   }
  83.  
  84.   if(!(GfxBase=(struct GfxBase *)OpenLibrary("graphics.library",37)))
  85.   {
  86.     Alert(AN_Unknown|AG_OpenLib|AO_GraphicsLib);
  87.     return 1;
  88.   }
  89.  
  90.   if(!(IntuitionBase=(struct IntuitionBase *)OpenLibrary("intuition.library",37)))
  91.   {
  92.     Alert(AN_Unknown|AG_OpenLib|AO_Intuition);
  93.     return 1;
  94.   }
  95.  
  96.   if(!(UtilityBase=OpenLibrary("utility.library",37)))
  97.   {
  98.     Alert(AN_Unknown|AG_OpenLib|AO_UtilityLib);
  99.     return 1;
  100.   }
  101.  
  102.   if(!(AslBase=OpenLibrary("asl.library",37)))
  103.   {
  104.     struct EasyStruct req = { sizeof (struct EasyStruct),
  105.         0, _LibName, "Cannot open 'asl.library' v37", "OK"};
  106.  
  107.        EasyRequest( NULL, &req, NULL, NULL );
  108.     return 0;
  109.   }
  110.  
  111. // Don't fail if this one doesn't open!
  112.   DataTypesBase=OpenLibrary("datatypes.library",39);
  113.  
  114.   return 0;
  115. }
  116.  
  117. void __saveds __asm __UserLibCleanup (register __a6 struct Library *libbase)
  118. {
  119.   if(AslBase)       { CloseLibrary(AslBase); AslBase=NULL; }
  120.   if(DOSBase)       { CloseLibrary((struct Library *)DOSBase); DOSBase=NULL; }
  121.   if(GfxBase)       { CloseLibrary((struct Library *)GfxBase); GfxBase=NULL; }
  122.   if(IntuitionBase) { CloseLibrary((struct Library *)IntuitionBase); IntuitionBase=NULL; }
  123.   if(UtilityBase)   { CloseLibrary(UtilityBase); UtilityBase=NULL; }
  124.   if(DataTypesBase) { CloseLibrary(DataTypesBase); DataTypesBase=NULL; }
  125. }
  126.  
  127. ULONG __asm __saveds intAHIsub_AllocAudio(
  128.     register __a1 struct TagItem *tagList,
  129.     register __a2 struct AHIAudioCtrlDrv *AudioCtrl )
  130. {
  131.   if(AslBase == NULL)
  132.   {
  133.     return AHISF_ERROR;
  134.   }
  135.  
  136.   if(AudioCtrl->ahiac_DriverData=AllocVec(sizeof(struct filesave),MEMF_CLEAR))
  137.   {
  138.     dd->fs_AHIsubBase=AHIsubBase;
  139.     dd->fs_DisableSignal=-1;
  140.     dd->fs_EnableSignal=-1;
  141.     dd->fs_SlaveSignal=-1;
  142.     dd->fs_MasterSignal=AllocSignal(-1);
  143.     dd->fs_MasterTask=(struct Process *)FindTask(NULL);
  144.  
  145.     dd->fs_RecSlaveSignal=-1;
  146.     dd->fs_RecMasterSignal=AllocSignal(-1);
  147.   }
  148.   else
  149.     return AHISF_ERROR;
  150.   if((dd->fs_MasterSignal EQ -1) || (dd->fs_RecMasterSignal EQ -1))
  151.     return AHISF_ERROR;
  152.  
  153.   dd->fs_Format=GetTagData(AHIDB_FileSaveFormat,FORMAT_8SVX,tagList);
  154.  
  155.   if(!(dd->fs_FileReq=AllocAslRequestTags(ASL_FileRequest,
  156.       ASLFR_InitialFile,
  157.           (dd->fs_Format EQ FORMAT_8SVX ? ".8SVX" :
  158.             (dd->fs_Format EQ FORMAT_AIFF ? ".AIFF" :
  159.               (dd->fs_Format EQ FORMAT_AIFC ? ".AIFC" : ""))),
  160.       ASLFR_DoSaveMode,TRUE,
  161.       ASLFR_RejectIcons,TRUE,
  162.       ASLFR_TitleText,_LibID,
  163.       TAG_DONE)))
  164.     return AHISF_ERROR;
  165.  
  166.   if(!(dd->fs_RecFileReq=AllocAslRequestTags(ASL_FileRequest,
  167.       ASLFR_RejectIcons,TRUE,
  168.       ASLFR_TitleText,"Select a sound sample",
  169.       TAG_DONE)))
  170.     return AHISF_ERROR;
  171.  
  172.   return AHISF_KNOWHIFI|AHISF_KNOWSTEREO|AHISF_CANRECORD|AHISF_MIXING|AHISF_TIMING;
  173. }
  174.  
  175. void __asm __saveds intAHIsub_FreeAudio(
  176.     register __a2 struct AHIAudioCtrlDrv *AudioCtrl )
  177. {
  178.   if(AudioCtrl->ahiac_DriverData)
  179.   {
  180.     FreeAslRequest(dd->fs_FileReq);
  181.     FreeAslRequest(dd->fs_RecFileReq);
  182.     FreeSignal(dd->fs_MasterSignal);
  183.     FreeSignal(dd->fs_RecMasterSignal);
  184.     FreeVec(AudioCtrl->ahiac_DriverData);
  185.     AudioCtrl->ahiac_DriverData=NULL;
  186.   }
  187. }
  188.  
  189. ULONG __asm __saveds intAHIsub_Start(
  190.     register __d0 ULONG Flags,
  191.     register __a2 struct AHIAudioCtrlDrv *AudioCtrl )
  192. {
  193.  
  194.   AHIsub_Stop(Flags,AudioCtrl);
  195.  
  196.   if(Flags & AHISF_PLAY)
  197.   {
  198.     ULONG savebufferlength;
  199.  
  200.     if(!(dd->fs_MixBuffer=AllocVec(AudioCtrl->ahiac_BuffSize,MEMF_ANY)))
  201.       return AHIE_NOMEM;
  202.  
  203.     dd->fs_SaveBufferSize=AudioCtrl->ahiac_MaxBuffSamples;
  204.     if(AudioCtrl->ahiac_Flags & AHIACF_STEREO)
  205.       dd->fs_SaveBufferSize <<=1;
  206.     if(dd->fs_SaveBufferSize < SAVEBUFFERSIZE)
  207.       dd->fs_SaveBufferSize = SAVEBUFFERSIZE;
  208.  
  209.     savebufferlength = dd->fs_SaveBufferSize;
  210.     if((dd->fs_Format EQ FORMAT_AIFF) || (dd->fs_Format EQ FORMAT_AIFC))
  211.       savebufferlength <<=1;
  212.  
  213.     if(!(dd->fs_SaveBuffer=AllocVec(savebufferlength,MEMF_ANY)))
  214.       return AHIE_NOMEM;
  215.  
  216.     if(AslRequestTags(dd->fs_FileReq,TAG_DONE))
  217.     {
  218.       Forbid();
  219.       if(dd->fs_SlaveTask=CreateNewProcTags(
  220.           NP_Entry,SlaveEntry,
  221.           NP_Name,_LibName,
  222.           NP_Priority,-1,               // It's a number cruncher...
  223.           TAG_DONE))
  224.         dd->fs_SlaveTask->pr_Task.tc_UserData=AudioCtrl;
  225.       Permit();
  226.       if(dd->fs_SlaveTask)
  227.       {
  228.         Wait(1L<<dd->fs_MasterSignal);  // Wait for slave to come alive
  229.         if(dd->fs_SlaveTask EQ NULL)    // Is slave alive or dead?
  230.           return AHIE_UNKNOWN;
  231.       }
  232.       else
  233.         return AHIE_NOMEM;
  234.     }
  235.     else
  236.       if(IoErr())
  237.         return AHIE_NOMEM;    //error occured
  238.       else
  239.         return AHIE_ABORTED;  //requester cancelled
  240.   }
  241.  
  242.   if(Flags & AHISF_RECORD)
  243.   {
  244.     if(!(dd->fs_RecBuffer=AllocVec(RECBUFFERSIZE*4,MEMF_ANY)))
  245.       return AHIE_NOMEM;
  246.  
  247.     if(AslRequestTags(dd->fs_RecFileReq,TAG_DONE))
  248.     {
  249.       Delay(TICKS_PER_SECOND);         // Wait for window to close etc...
  250.       Forbid();
  251.       if(dd->fs_RecSlaveTask=CreateNewProcTags(
  252.           NP_Entry,RecSlaveEntry,
  253.           NP_Name,_LibName,
  254.           NP_Priority,1,               // Make it steady...
  255.           TAG_DONE))
  256.         dd->fs_RecSlaveTask->pr_Task.tc_UserData=AudioCtrl;
  257.       Permit();
  258.       if(dd->fs_RecSlaveTask)
  259.       {
  260.         Wait(1L<<dd->fs_RecMasterSignal);  // Wait for slave to come alive
  261.         if(dd->fs_RecSlaveTask EQ NULL)    // Is slave alive or dead?
  262.           return AHIE_UNKNOWN;
  263.       }
  264.       else
  265.         return AHIE_NOMEM;
  266.     }
  267.     else
  268.       if(IoErr())
  269.         return AHIE_NOMEM;    //error occured
  270.       else
  271.         return AHIE_ABORTED;  //requester cancelled
  272.   }
  273.  
  274.   return AHIE_OK;
  275. }
  276.  
  277.  
  278. void __asm __saveds intAHIsub_Update(
  279.     register __d0 ULONG Flags,
  280.     register __a2 struct AHIAudioCtrlDrv *AudioCtrl )
  281. {
  282. }
  283.  
  284.  
  285. void __asm __saveds intAHIsub_Stop(
  286.     register __d0 ULONG Flags,
  287.     register __a2 struct AHIAudioCtrlDrv *AudioCtrl )
  288. {
  289.   if(Flags & AHISF_PLAY)
  290.   {
  291.     if(dd->fs_SlaveTask)
  292.     {
  293.       if(dd->fs_SlaveSignal != -1)
  294.         Signal((struct Task *)dd->fs_SlaveTask,1L<<dd->fs_SlaveSignal); // Kill him!
  295.       Wait(1L<<dd->fs_MasterSignal);  // Wait for slave to die
  296.     }
  297.     FreeVec(dd->fs_MixBuffer);
  298.     dd->fs_MixBuffer=NULL;
  299.     FreeVec(dd->fs_SaveBuffer);
  300.     dd->fs_SaveBuffer=NULL;
  301.   }
  302.  
  303.   if(Flags & AHISF_RECORD)
  304.   {
  305.     if(dd->fs_RecSlaveTask)
  306.     {
  307.       if(dd->fs_RecSlaveSignal != -1)
  308.         Signal((struct Task *)dd->fs_RecSlaveTask,1L<<dd->fs_RecSlaveSignal); // Kill him!
  309.       Wait(1L<<dd->fs_RecMasterSignal);  // Wait for slave to die
  310.     }
  311.     FreeVec(dd->fs_RecBuffer);
  312.     dd->fs_RecBuffer=NULL;
  313.   }
  314. }
  315.  
  316.  
  317.  
  318. LONG __asm __saveds intAHIsub_GetAttr(
  319.     register __d0 ULONG Attribute,
  320.     register __d1 LONG Argument,
  321.     register __d2 LONG Default,
  322.     register __a1 struct TagItem *tagList,
  323.     register __a2 struct AHIAudioCtrlDrv *AudioCtrl)
  324. {
  325.   int i;
  326.   switch(Attribute)
  327.   {
  328.   case AHIDB_Bits:
  329.     if(GetTagData(AHIDB_FileSaveFormat,FORMAT_8SVX,tagList) EQ FORMAT_8SVX)
  330.       return 8;
  331.     else
  332.       return 16;
  333.   case AHIDB_Frequencies:
  334.     return FREQUENCIES;
  335.   case AHIDB_Frequency: // Index->Frequency
  336.     return (LONG) frequency[Argument];
  337.   case AHIDB_Index: // Frequency->Index
  338.     if(Argument<=frequency[0])
  339.       return 0;
  340.     if(Argument>=frequency[FREQUENCIES-1])
  341.       return FREQUENCIES-1;
  342.     for(i=1;i<FREQUENCIES;i++)
  343.       if(frequency[i]>Argument)
  344.       {
  345.         if( (Argument-frequency[i-1]) < (frequency[i]-Argument) )
  346.           return i-1;
  347.         else
  348.           return i;
  349.       }
  350.     return NULL;  // Will not happen
  351.   case AHIDB_Author:
  352.     return (LONG) "Martin 'Leviticus' Blom";
  353.   case AHIDB_Copyright:
  354.     return (LONG) "Public Domain";
  355.   case AHIDB_Version:
  356.     return (LONG) _LibID;
  357.   case AHIDB_Record:
  358.   case AHIDB_FullDuplex:
  359.     return TRUE;
  360.   case AHIDB_MaxRecordSamples:
  361.     return RECBUFFERSIZE;
  362.   case AHIDB_Realtime:
  363.     return FALSE;
  364.   case AHIDB_Inputs:
  365.     return 1;
  366.   case AHIDB_Input:
  367.     return (LONG) "File";    // We have only one input!
  368.   case AHIDB_Outputs:
  369.     return 1;
  370.   case AHIDB_Output:
  371.     return (LONG) "File";    // We have only one output!
  372.   default:
  373.     return Default;
  374.   }
  375. }
  376.  
  377.  
  378. ULONG __asm __saveds intAHIsub_HardwareControl(
  379.     register __d0 ULONG attribute,
  380.     register __d1 LONG argument,
  381.     register __a2 struct AHIAudioCtrlDrv *AudioCtrl )
  382. {
  383.   return NULL;
  384. }
  385.  
  386. /*
  387. ** Unused LVOs follows...
  388. */
  389.  
  390. ULONG __asm __saveds intAHIsub_SetVol(
  391.     register __d0 UWORD channel,
  392.     register __d1 Fixed volume,
  393.     register __d2 sposition pan,
  394.     register __a2 struct AHIAudioCtrlDrv *AudioCtrl,
  395.     register __d3 ULONG Flags)
  396. {
  397.   return AHIS_UNKNOWN;
  398. }
  399.  
  400. ULONG __asm __saveds intAHIsub_SetFreq(
  401.     register __d0 UWORD channel,
  402.     register __d1 ULONG freq,
  403.     register __a2 struct AHIAudioCtrlDrv *AudioCtrl,
  404.     register __d2 ULONG flags )
  405. {
  406.   return AHIS_UNKNOWN;
  407. }
  408.  
  409. ULONG __asm __saveds intAHIsub_SetSound(
  410.     register __d0 UWORD channel,
  411.     register __d1 UWORD sound,
  412.     register __d2 ULONG offset,
  413.     register __d3 LONG length,
  414.     register __a2 struct AHIAudioCtrlDrv *AudioCtrl,
  415.     register __d4 ULONG flags )
  416. {
  417.   return AHIS_UNKNOWN;
  418. }
  419.  
  420.  
  421. ULONG __asm __saveds intAHIsub_SetEffect (
  422.     register __a0 APTR effect,
  423.     register __a2 struct AHIAudioCtrlDrv *AudioCtrl )
  424. {
  425.   return AHIS_UNKNOWN;
  426. }
  427.  
  428. ULONG __asm __saveds intAHIsub_LoadSound(
  429.     register __d0 UWORD sound,
  430.     register __d1 ULONG type,
  431.     register __a0 APTR info,
  432.     register __a2 struct AHIAudioCtrlDrv *AudioCtrl )
  433. {
  434.   return AHIS_UNKNOWN;
  435. }
  436.  
  437. ULONG __asm __saveds intAHIsub_UnloadSound(
  438.     register __d0 UWORD sound,
  439.     register __a2 struct AHIAudioCtrlDrv *AudioCtrl )
  440. {
  441.   return AHIS_UNKNOWN;
  442. }
  443.  
  444.  
  445.  
  446. /*
  447. ** The slave process
  448. */
  449.  
  450. void __asm __saveds SlaveTask(register __a2 struct AHIAudioCtrlDrv *AudioCtrl)
  451. // SlaveEntry() will set up register a2 and a6 for us. __saveds takes care of a4.
  452. {
  453.   struct {
  454.     ULONG                 FORMid;
  455.     ULONG                 FORMsize;
  456.     ULONG                 AIFCid;
  457.  
  458.     ULONG                 FVERid;
  459.     ULONG                 FVERsize;
  460.     FormatVersionHeader   FVERchunk;
  461.  
  462.     ULONG                 COMMid;
  463.     ULONG                 COMMsize;
  464.     ExtCommonChunk        COMMchunk;
  465.  
  466.     ULONG                 SSNDid;
  467.     ULONG                 SSNDsize;
  468.     SampledSoundHeader    SSNDchunk;
  469.   } AIFCheader = 
  470.     { // All NULLs will be filled later.
  471.       ID_FORM,NULL,ID_AIFC,
  472.       ID_FVER,sizeof(FormatVersionHeader),{AIFCVersion1},
  473.       ID_COMM,sizeof(ExtCommonChunk),{NULL,NULL,16,{NULL},NO_COMPRESSION,
  474.           sizeof("not compressed")-1,'n','o','t',' ','c','o','m','p','r','e','s','s','e','d'},
  475.       ID_SSND,NULL,{0,0}
  476.     };
  477.   struct {
  478.     ULONG                 FORMid;
  479.     ULONG                 FORMsize;
  480.     ULONG                 AIFFid;
  481.  
  482.     ULONG                 COMMid;
  483.     ULONG                 COMMsize;
  484.     CommonChunk           COMMchunk;
  485.  
  486.     ULONG                 SSNDid;
  487.     ULONG                 SSNDsize;
  488.     SampledSoundHeader    SSNDchunk;
  489.   } AIFFheader = 
  490.     { // All NULLs will be filled later.
  491.       ID_FORM,NULL,ID_AIFF,
  492.       ID_COMM,sizeof(CommonChunk),{NULL,NULL,16,{NULL}},
  493.       ID_SSND,NULL,{0,0}
  494.     };
  495.   struct {
  496.     ULONG                 FORMid;
  497.     ULONG                 FORMsize;
  498.     ULONG                 EIGHTSVXid;
  499.  
  500.     ULONG                 VHDRid;
  501.     ULONG                 VHDRsize;
  502.     Voice8Header          VHDRchunk;
  503.  
  504.     ULONG                 BODYid;
  505.     ULONG                 BODYsize;
  506.   } EIGHTSVXheader = 
  507.     { // All NULLs will be filled later.
  508.       ID_FORM,NULL,ID_8SVX,
  509.       ID_VHDR,sizeof(Voice8Header),{NULL,0,0,NULL,1,sCmpNone,0x10000},
  510.       ID_BODY,NULL
  511.     };
  512.   struct EasyStruct req = {
  513.     sizeof (struct EasyStruct),
  514.     0,
  515.     _LibID,
  516.     "Rendering finished.\nTo futher improve the quality of the sample,\nyou can raise the volume to %ld%%%sand render again.",
  517.     "OK",
  518.   };
  519.  
  520.   BPTR lock=NULL,cd=NULL,file=NULL;
  521.   ULONG signals,i,maxVolume=0;
  522.   ULONG samples,length,offset=0,bytesInBuffer=0,samplesWritten=0,bytesWritten=0;
  523.  
  524. // We cannot handle stereo 8SVXs!
  525.   if( (dd->fs_Format EQ FORMAT_8SVX) &&
  526.       (AudioCtrl->ahiac_Flags & AHIACF_STEREO) )
  527.     goto quit;
  528.  
  529.   if((dd->fs_DisableSignal=AllocSignal(-1)) EQ -1)
  530.     goto quit;
  531.   if((dd->fs_EnableSignal=AllocSignal(-1)) EQ -1)
  532.     goto quit;
  533.   if((dd->fs_SlaveSignal=AllocSignal(-1)) EQ -1)
  534.     goto quit;
  535.  
  536.   if(!(lock=Lock(dd->fs_FileReq->fr_Drawer,ACCESS_READ)))
  537.     goto quit;
  538.   cd = CurrentDir(lock);
  539.   if(!(file=Open(dd->fs_FileReq->fr_File,MODE_NEWFILE)))
  540.     goto quit;
  541.  
  542.   switch(dd->fs_Format)
  543.   {
  544.     case FORMAT_8SVX:
  545.       Write(file,&EIGHTSVXheader,sizeof EIGHTSVXheader);
  546.       break;
  547.     case FORMAT_AIFF:
  548.       Write(file,&AIFFheader,sizeof AIFFheader);
  549.       break;
  550.     case FORMAT_AIFC:
  551.       Write(file,&AIFCheader,sizeof AIFCheader);
  552.       break;
  553.   }
  554.  
  555.   // Everything set up. Tell Master we're alive and healthy.
  556.   Signal((struct Task *)dd->fs_MasterTask,1L<<dd->fs_MasterSignal);
  557.  
  558.   for(;;)
  559.   {
  560.     signals=SetSignal(0L,0L);
  561.     if(signals & (SIGBREAKF_CTRL_C | 1L<<dd->fs_SlaveSignal))
  562.       break;
  563.     if(signals & (1L<<dd->fs_EnableSignal | 1L<<dd->fs_DisableSignal) EQ 1L<<dd->fs_DisableSignal)
  564.       Wait(1L<<dd->fs_EnableSignal);
  565.     CallHookPkt(AudioCtrl->ahiac_PlayerFunc,AudioCtrl,NULL);
  566.     CallHookPkt(AudioCtrl->ahiac_MixerFunc,AudioCtrl,dd->fs_MixBuffer);
  567.  
  568.     samples=AudioCtrl->ahiac_BuffSamples*(AudioCtrl->ahiac_Flags & AHIACF_STEREO ? 2 : 1);
  569.  
  570. // Search for loudest part in sample
  571.     if(AudioCtrl->ahiac_Flags & AHIACF_HIFI)
  572.     {
  573.       for(i=0;i<samples;i++)
  574.         if(abs(((LONG *)dd->fs_MixBuffer)[i])>maxVolume)
  575.           maxVolume=abs(((LONG *)dd->fs_MixBuffer)[i]);
  576.     }
  577.     else
  578.     {
  579.       for(i=0;i<samples;i++)
  580.         if(abs(((WORD *)dd->fs_MixBuffer)[i])>maxVolume)
  581.           maxVolume=abs(((WORD *)dd->fs_MixBuffer)[i]);
  582.     }
  583.  
  584.     if(offset+samples >= dd->fs_SaveBufferSize)
  585.     {
  586.       if(Write(file,dd->fs_SaveBuffer,bytesInBuffer) != bytesInBuffer)
  587.         break;
  588.       offset=0;
  589.       bytesInBuffer=0;
  590.     }
  591.  
  592.     switch(dd->fs_Format)
  593.     {
  594.       case FORMAT_8SVX:
  595.         if(AudioCtrl->ahiac_Flags & AHIACF_HIFI)
  596.         {
  597.           BYTE *dest=&((BYTE *) dd->fs_SaveBuffer)[offset];
  598.           LONG *source=dd->fs_MixBuffer;
  599.  
  600.           for(i=0;i<samples;i++)
  601.             *dest++=*source++ >> 24;
  602.         }
  603.         else
  604.         {
  605.           BYTE *dest=&((BYTE *) dd->fs_SaveBuffer)[offset];
  606.           WORD *source=dd->fs_MixBuffer;
  607.  
  608.           for(i=0;i<samples;i++)
  609.             *dest++=*source++ >> 8;
  610.         }
  611.         length=samples;
  612.         break;
  613.  
  614.       case FORMAT_AIFF:
  615.       case FORMAT_AIFC:
  616.         if(AudioCtrl->ahiac_Flags & AHIACF_HIFI)
  617.         {
  618.           WORD *dest=&((WORD *) dd->fs_SaveBuffer)[offset];
  619.           LONG *source=dd->fs_MixBuffer;
  620.  
  621.           for(i=0;i<samples;i++)
  622.             *dest++=*source++ >> 16;
  623.         }
  624.         else
  625.         {
  626.           WORD *dest=&((WORD *) dd->fs_SaveBuffer)[offset];
  627.           WORD *source=dd->fs_MixBuffer;
  628.  
  629.           for(i=0;i<samples;i++)
  630.             *dest++=*source++;
  631.         }
  632.         length=samples*2;
  633.         break;
  634.     }
  635.  
  636.     offset += samples;
  637.     samplesWritten += AudioCtrl->ahiac_BuffSamples;
  638.     bytesWritten += length;
  639.     bytesInBuffer += length;
  640.  
  641.   }
  642.  
  643.   Write(file,dd->fs_SaveBuffer,bytesInBuffer);
  644.  
  645.   switch(dd->fs_Format)
  646.   {
  647.     case FORMAT_8SVX:
  648.       EIGHTSVXheader.FORMsize=sizeof(EIGHTSVXheader)-8+bytesWritten;
  649.       EIGHTSVXheader.VHDRchunk.oneShotHiSamples=samplesWritten;
  650.       EIGHTSVXheader.VHDRchunk.samplesPerSec=AudioCtrl->ahiac_MixFreq;
  651.       EIGHTSVXheader.BODYsize=bytesWritten;
  652.       if(bytesWritten & 1)
  653.         FPutC(file,'\0');   // Pad to even
  654.       Seek(file,0,OFFSET_BEGINNING);
  655.       Write(file,&EIGHTSVXheader,sizeof EIGHTSVXheader);
  656.       break;
  657.  
  658.     case FORMAT_AIFF:
  659.       AIFFheader.FORMsize=sizeof(AIFFheader)-8+bytesWritten;
  660.       AIFFheader.COMMchunk.numChannels=(AudioCtrl->ahiac_Flags & AHIACF_STEREO ? 2 : 1);
  661.       AIFFheader.COMMchunk.numSampleFrames=samplesWritten;
  662.       ulong2extended(AudioCtrl->ahiac_MixFreq,&AIFFheader.COMMchunk.sampleRate);
  663.       AIFFheader.SSNDsize=sizeof(SampledSoundHeader)+bytesWritten;
  664.       Seek(file,0,OFFSET_BEGINNING);
  665.       Write(file,&AIFFheader,sizeof AIFFheader);
  666.       break;
  667.  
  668.     case FORMAT_AIFC:
  669.       AIFCheader.FORMsize=sizeof(AIFCheader)-8+bytesWritten;
  670.       AIFCheader.COMMchunk.numChannels=(AudioCtrl->ahiac_Flags & AHIACF_STEREO ? 2 : 1);
  671.       AIFCheader.COMMchunk.numSampleFrames=samplesWritten;
  672.       ulong2extended(AudioCtrl->ahiac_MixFreq,&AIFCheader.COMMchunk.sampleRate);
  673.       AIFCheader.SSNDsize=sizeof(SampledSoundHeader)+bytesWritten;
  674.       Seek(file,0,OFFSET_BEGINNING);
  675.       Write(file,&AIFCheader,sizeof AIFCheader);
  676.       break;
  677.   }
  678.  
  679.   if(AudioCtrl->ahiac_Flags & AHIACF_HIFI)
  680.     maxVolume >>=16;
  681.  
  682.   if(maxVolume!=0)
  683.     EasyRequest(NULL, &req, NULL, 3276800/maxVolume,
  684.       AudioCtrl->ahiac_MixFreq<frequency[FREQUENCIES-1] ? ",\nincrease the mixing frequency " : "\n");
  685.  
  686. quit:
  687.   if(file)
  688.   {
  689.     Close(file);
  690.   }
  691.   if(lock)
  692.   {
  693.     CurrentDir(cd);
  694.     UnLock(lock);
  695.   }
  696.   Forbid();
  697.   dd->fs_SlaveTask=NULL;
  698.   FreeSignal(dd->fs_DisableSignal);
  699.   FreeSignal(dd->fs_EnableSignal);
  700.   FreeSignal(dd->fs_SlaveSignal);
  701.   dd->fs_DisableSignal=-1;
  702.   dd->fs_EnableSignal=-1;
  703.   dd->fs_SlaveSignal=-1;
  704.   // Tell the Master we're dying
  705.   Signal((struct Task *)dd->fs_MasterTask,1L<<dd->fs_MasterSignal);
  706.   // Multitaking will resume when we are dead.
  707. }
  708.  
  709. /*
  710. ** Apple's 80-bit SANE extended has the following format:
  711.  
  712.  1       15      1            63
  713. +-+-------------+-+-----------------------------+
  714. |s|       e     |i|            f                |
  715. +-+-------------+-+-----------------------------+
  716.   msb        lsb   msb                       lsb
  717.  
  718. The value v of the number is determined by these fields as follows:
  719. If 0 <= e < 32767,              then v = (-1)^s * 2^(e-16383) * (i.f).
  720. If e == 32767 and f == 0,       then v = (-1)^s * (infinity), regardless of i.
  721. If e == 32767 and f != 0,       then v is a NaN, regardless of i.
  722. */
  723.  
  724. void ulong2extended (ULONG in, extended *ex)
  725. {
  726.   ex->exponent=31+16383;
  727.   ex->mantissa[1]=0;
  728.   while(!(in & 0x80000000))
  729.   {
  730.     ex->exponent--;
  731.     in<<=1;
  732.   }
  733.   ex->mantissa[0]=in;
  734. }
  735.  
  736.  
  737.  
  738. /*
  739. ** The record slave process
  740. */
  741.  
  742. void __asm __saveds RecSlaveTask(register __a2 struct AHIAudioCtrlDrv *AudioCtrl)
  743. // RecSlaveEntry() will set up register a2 and a6 for us. __saveds takes care of a4.
  744. {
  745.   ULONG   signals;
  746.   BPTR    lock=NULL,cd,file=NULL;
  747.   Object *o=NULL;
  748.   BYTE   *samples=NULL;
  749.   ULONG   length=NULL;
  750.   ULONG   count=0,offs=0,i;
  751.  
  752.   struct AHIRecordMessage RecordMessage=
  753.   {
  754.     AHIST_S16S,
  755.     NULL,
  756.     RECBUFFERSIZE
  757.   };
  758.  
  759.   RecordMessage.ahirm_Buffer=dd->fs_RecBuffer;
  760.  
  761.   if(!(lock=Lock(dd->fs_RecFileReq->fr_Drawer,ACCESS_READ)))
  762.     goto quit;
  763.   cd=CurrentDir(lock);
  764.  
  765.   if(DataTypesBase)
  766.   {
  767.     if (!(o = NewDTObject (dd->fs_RecFileReq->fr_File,
  768.         DTA_GroupID,GID_SOUND,
  769.         TAG_DONE)))
  770.       goto quit;
  771.  
  772.     GetDTAttrs(o,
  773.       SDTA_Sample,&samples,
  774.       SDTA_SampleLength,&length,
  775.       TAG_DONE);
  776.   }
  777.   else // datatypes.library not open. Open the selected file as raw 8 bit signed instead.
  778.   {
  779.     if(!(file=Open(dd->fs_RecFileReq->fr_File,MODE_OLDFILE)))
  780.       goto quit;
  781.     Seek(file,0,OFFSET_END);
  782.     length=Seek(file,0,OFFSET_BEGINNING);
  783.     if(!(samples=AllocVec(length,MEMF_ANY)))
  784.       goto quit;
  785.     if(length != Read(file,samples,length))
  786.       goto quit;
  787.   }
  788.  
  789.   if(!samples || !length )
  790.     goto quit;
  791.  
  792.   if((dd->fs_RecSlaveSignal=AllocSignal(-1)) EQ -1)
  793.     goto quit;
  794.  
  795. // Everything set up. Tell Master we're alive and healthy.
  796.     Signal((struct Task *)dd->fs_MasterTask,1L<<dd->fs_RecMasterSignal);
  797.  
  798.     for(;;)
  799.     {
  800.       signals=SetSignal(0L,0L);
  801.       if(signals & (SIGBREAKF_CTRL_C | 1L<<dd->fs_RecSlaveSignal))
  802.         break;
  803.  
  804.       for(;;)
  805.       {
  806.         if(count+RECBUFFERSIZE-offs < length)
  807.         {
  808. // End of sample will not be reached; just fill to the end of dd->fs_RecBuffer.
  809.           for(i=RECBUFFERSIZE-offs;i>0;i--)
  810.           {
  811.             dd->fs_RecBuffer[(offs)<<1]=
  812.             dd->fs_RecBuffer[((offs++)<<1)+1]=
  813.             samples[count++]<<8;
  814.           }
  815.           offs=0;
  816.           break;
  817.         }
  818.         else
  819.         {
  820. // End of sample will be reached. Fill part of buffer, and iterate (== don't break).
  821.           for(i=length-count;i>0;i--)
  822.           {
  823.             dd->fs_RecBuffer[(offs)<<1]=
  824.             dd->fs_RecBuffer[((offs++)<<1)+1]=
  825.             samples[count++]<<8;
  826.           }
  827.           count=0;
  828.         }
  829.  
  830.       }
  831.  
  832.       CallHookPkt(AudioCtrl->ahiac_SamplerFunc,AudioCtrl,&RecordMessage);
  833.       Delay(50*RECBUFFERSIZE/AudioCtrl->ahiac_MixFreq);
  834.     }
  835.  
  836. quit:
  837. // Get rid of object
  838.   if(DataTypesBase)
  839.   {
  840.     if(o)
  841.       DisposeDTObject (o);
  842.   }
  843.   else // datatypes.library not open.
  844.   {
  845.     if(samples)
  846.       FreeVec(samples);
  847.     if(file)
  848.       Close(file);
  849.   }
  850.   CurrentDir(cd);
  851.   if(lock)
  852.     UnLock(lock);
  853.  
  854.   Forbid();
  855.   dd->fs_RecSlaveTask=NULL;
  856.   FreeSignal(dd->fs_RecSlaveSignal);
  857.   dd->fs_RecSlaveSignal=-1;
  858.   // Tell the Master we're dying
  859.   Signal((struct Task *)dd->fs_MasterTask,1L<<dd->fs_RecMasterSignal);
  860.   // Multitaking will resume when we are dead.
  861. }
  862.